﻿module public UriParsing

open System
open System.Text.RegularExpressions
open Utils
open Uris

let parseUrl (url:string) (refUrl:HttpUrl option) =     
    let scheme, rest =
        let m = Regex.Match(url, "^(?<scheme>\w+)\:")
        if m.Success then
            let scheme = m.Groups.["scheme"].Value
            let rest = url.Substring(m.Length)
            scheme, rest
        else 
            // no scheme - use from ref
            if refUrl = None then failwith "scheme missing"
            refUrl.Value.scheme, url

    let (host, port), rest =
        let m = Regex.Match(rest, "^//(?<host>[^\s/]+)")
        if m.Success then
            let host = m.Groups.["host"].Value
            let host, port =
                if host.Contains(":") then 
                    let host, port = partition host ":"
                    host, Some(Int32.Parse(port))
                else 
                    host, None
            (host, port), (rest.Substring(m.Length))
        else
            match refUrl with
            | Some ruri -> (ruri.authority), rest
            | None -> failwith "host missing"

    let absPath, rest =
        if rest.StartsWith("/")
        then
            let m = Regex.Match(rest, "^(?<abspath>/[^#?]*)") 
            m.Groups.["abspath"].Value, rest.Substring(m.Length)
        else 
            match refUrl with
            | Some ruri -> ruri.path, rest
            | None -> failwith "absolute path missing"

    let queryString, rest =
        if rest.StartsWith("?")
        then
            let m = Regex.Match(rest, "^(?<query>/[^#]*)") 
            m.Groups.["query"].Value, rest.Substring(m.Length)
        else 
            "", rest

    let fragment = rest
    {scheme=scheme;host=host;port=port;path=absPath;queryString=queryString;fragment=fragment}


let blankUri = {scheme="about"; host="blank"; port=None; path=""; queryString=""; fragment=""}


let urlEncode (str:string) = 
    let str = Regex.Replace(str, "[^a-zA-Z0-9 -_.~]", (fun (m:Match)->
                                let codePoint = int(m.Value.[0])
                                let hex = codePoint.ToString("X")
                                "%" + hex)) 
    str.Replace(" ", "+")